Skip to content

feat(client-core): Introduce formating API#10653

Merged
ovr merged 11 commits intomasterfrom
feat/client-core-formatting
Apr 9, 2026
Merged

feat(client-core): Introduce formating API#10653
ovr merged 11 commits intomasterfrom
feat/client-core-formatting

Conversation

@ovr
Copy link
Copy Markdown
Member

@ovr ovr commented Apr 8, 2026

No description provided.

ovr added 4 commits April 8, 2026 18:41
…cale option

Replace hardcoded en-US locale with Intl.NumberFormat-derived locale that
resolves decimal/thousands separators and currency symbol position from
the runtime. Add locale option to FormatValueOptions, cached per
locale:currency pair. Extract FormatValueMember type.
@ovr ovr requested a review from a team as a code owner April 8, 2026 16:43
@github-actions github-actions bot added client:core Issues relating to the JavaScript client SDK javascript Pull requests that update Javascript code labels Apr 8, 2026
@claude
Copy link
Copy Markdown

claude bot commented Apr 8, 2026

Claude finished @ovr's task in 2m 59s —— View job


PR Review: feat(client-core): Support format

  • Read and analyze all changed files
  • Review code quality and best practices
  • Review security considerations
  • Review performance
  • Review test coverage
  • Post comprehensive review

Summary

This PR adds a formatValue utility to @cubejs-client/core that formats numbers, currencies, percentages, and time values using d3-format/d3-time-format, with locale support derived from the Intl API. The implementation is clean and well-structured overall. 6 inline comments posted on specific issues.

What's Good

  • Smart locale derivation: Using Intl.NumberFormat.formatToParts() to build d3 locale definitions is a solid approach — it leverages the platform's locale data without bundling CLDR.
  • Locale caching: The localeCache avoids recreating d3 locale objects on every call.
  • Clean type design: FormatValueOptions extends FormatValueMember cleanly, and the JSDoc comments on each field are helpful.
  • Good test coverage of the main formatting paths (currency, percent, number, custom-numeric, custom-time, passthrough, locale).

Key Issues

Priority Issue Location
🔴 High Export is commented out — consumers can't use formatValue. Needs clarity on the access strategy. index.ts:913-914
🟡 Medium parseNumber returns NaN for non-numeric strings — d3 will render literal "NaN" in the UI. Should handle gracefully. format.ts:70-76
🟡 Medium Hardcoded grouping: [3] ignores locales with non-uniform grouping (e.g., en-IN uses [3, 2]). format.ts:24-26
🟢 Low getCurrentLocale() allocates a new Intl.NumberFormat on every call — can be cached. format.ts:41-43
🟢 Low Currency code leaks into cache key for non-currency formats, causing duplicate cache entries. format.ts:119-122
🟢 Low Missing test edge cases: NaN input, invalid dates, custom emptyPlaceholder, very large numbers. format.test.ts:84

Security

No concerns — this is a pure formatting utility with no network calls, DOM manipulation, or dynamic code execution.

Verdict

The core logic is sound and well-tested for happy paths. The commented-out export is the most important question — it determines whether this feature is actually shippable in this PR or a foundation for a follow-up. The NaN handling should also be addressed before merge to avoid rendering "NaN" in production UIs.

Comment on lines +913 to +914
// We don't export it for now, because size of builds for cjs/umd users will be affected
// export * from './format';
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The export is commented out — meaning consumers can't actually use formatValue via the standard @cubejs-client/core import.

Is this intentional for this PR? If so, how are consumers expected to access this function? If this is meant to be usable in a follow-up (e.g., only from ESM builds), it might be worth adding a note in the PR description about the plan.

If tree-shaking is the concern, modern bundlers (Rollup, webpack, esbuild) will eliminate unused exports from ESM builds. The CJS/UMD concern is valid, but you could consider a separate entry point (e.g., @cubejs-client/core/format) instead of blocking the export entirely.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Intended for now, I will prepare separate entrypoints in different PR, It require testing

@codecov
Copy link
Copy Markdown

codecov bot commented Apr 8, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 57.84%. Comparing base (05ab975) to head (ec061d9).
⚠️ Report is 11 commits behind head on master.

Additional details and impacted files
@@           Coverage Diff           @@
##           master   #10653   +/-   ##
=======================================
  Coverage   57.84%   57.84%           
=======================================
  Files         215      215           
  Lines       16609    16609           
  Branches     3336     3336           
=======================================
  Hits         9607     9607           
  Misses       6514     6514           
  Partials      488      488           
Flag Coverage Δ
cube-backend 57.84% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@ovr ovr closed this Apr 8, 2026
@ovr ovr reopened this Apr 8, 2026
@claude
Copy link
Copy Markdown

claude bot commented Apr 8, 2026

Claude finished @ovr's task in 2m 47s —— View job


PR Review: feat(client-core): Support format

  • Read and analyze all changed files
  • Review code quality and best practices
  • Review security considerations
  • Review performance
  • Review test coverage
  • Post comprehensive review

Summary

This PR adds a formatValue utility to @cubejs-client/core that formats numbers, currencies, percentages, and time values using d3-format/d3-time-format, with locale support derived from the Intl API. 5 inline comments posted on specific issues.

What's Improved Since Last Review

  • Locale detection is now cached (203919c): detectLocale() runs once at module load and stores the result in currentLocale, addressing the prior feedback about allocating Intl.NumberFormat on every call.

What's Good

  • Smart locale derivation: Using Intl.NumberFormat.formatToParts() to build d3 locale definitions leverages the platform's locale data without bundling CLDR — clean approach.
  • Locale caching: The localeCache with Object.create(null) avoids recreating d3 locale objects on every call.
  • Clean type design: FormatValueOptions extends FormatValueMember cleanly, and the JSDoc comments are helpful. The types align well with the existing Annotation and BaseCubeMember types in types.ts.
  • Good test coverage of the main formatting paths (currency, percent, number, custom-numeric, custom-time, passthrough, locale, grain-based time).
  • Graceful fallback for locale detection: The try/catch in detectLocale() with en-US fallback handles environments where Intl might not be available.

Remaining Issues

Priority Issue Location
🔴 High Export is commented out — consumers can't use formatValue. Needs clarity on the access strategy or a note in the PR description. index.ts:913-914
🟡 Medium parseNumber returns NaN for non-numeric strings — d3 will render literal "NaN" in the UI. Should return null and fall back to emptyPlaceholder. format.ts:78-84
🟡 Medium new Date() on invalid input produces Invalid DatetimeFormat silently outputs "NaN" placeholders for each directive. Should validate and fall back. format.ts:142
🟢 Low Currency code leaks into cache key for non-currency formats, causing duplicate cache entries for percent and number formats. format.ts:128-130
🟢 Low Missing test edge cases: NaN input, invalid dates, custom emptyPlaceholder, empty string with numeric format. format.test.ts:84

Security

No concerns — this is a pure formatting utility with no network calls, DOM manipulation, or dynamic code execution.

Verdict

The core logic is sound and well-tested for happy paths. The commented-out export is the most important question — it determines whether this feature is actually shippable or a foundation for a follow-up. The NaN/invalid date handling should be addressed before merge to avoid rendering "NaN" in production UIs — these are the most likely edge cases users will hit with real-world data.

Comment on lines +913 to +914
// We don't export it for now, because size of builds for cjs/umd users will be affected
// export * from './format';
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The export is still commented out — consumers can't access formatValue via the standard @cubejs-client/core import.

Is this intentional for this PR? If the concern is bundle size for CJS/UMD users, a separate entry point (e.g., @cubejs-client/core/format) could expose it without affecting existing builds. Alternatively, modern bundlers tree-shake unused ESM exports effectively.

If this is meant to land without the export, it might be worth noting in the PR description that this is a foundational PR with a follow-up planned to wire the export.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Intended for now, I will prepare separate entrypoints in different PR, It require testing

@ovr ovr force-pushed the feat/client-core-formatting branch from 79011b2 to ec061d9 Compare April 9, 2026 12:30
@ovr ovr changed the title feat(client-core): Support format feat(client-core): Introduce formating API Apr 9, 2026
@ovr ovr requested a review from vasilev-alex April 9, 2026 12:33
@cube-js cube-js deleted a comment from claude bot Apr 9, 2026
@ovr ovr requested a review from MikeNitsenko April 9, 2026 12:35
@ovr ovr merged commit 971b9f6 into master Apr 9, 2026
44 checks passed
@ovr ovr deleted the feat/client-core-formatting branch April 9, 2026 17:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

client:core Issues relating to the JavaScript client SDK javascript Pull requests that update Javascript code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants